using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using SimpleJSON;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace Gj
{
    [InitializeOnLoad]
    public class BuildEditor
    {
        private const string bundleDirectory = "Assets/Resources/Bundle";
        private const string resourceDirectory = "Assets/Resources/";

        // Bundle option
        private static string targetDirectory = "Assets/StreamingAssets/Namespace";
        // Bundle option
        private static string projectDirectory = "Assets/StreamingAssets/Namespace";

        // Build option
        private static string version = "";
        private static string buildNumber = "";
        private static string define = "";
        private static string nss = "";
        private static bool forceNamespace = false;

        private static bool ios = false;
        private static bool android = false;
        private static bool osx = false;
        private static bool win = false;
        private static bool bundle = false;

        private static bool debug = false;

        private static bool server = false;


        public static void Namespace()
        {
            ParseArgs();
            // bundle
            BundleProcess(AssetBundleOptimize.None);
            // project
            ProjectProcess();
        }

        public static void ParseArgs()
        {
            //在这里分析shell传入的参数， 还记得上面我们说的哪个 project-$1 这个参数吗？
            //这里遍历所有参数，找到 project开头的参数， 然后把-符号 后面的字符串返回，
            //这个字符串就是 91 了。。
            foreach (string arg in System.Environment.GetCommandLineArgs())
            {
                if (arg.StartsWith("--version="))
                {
                    version = arg.Split('=')[1];
                }
                else if (arg.StartsWith("--buildNumber="))
                {
                    buildNumber = arg.Split('=')[1];
                }
                else if (arg.StartsWith("--define="))
                {
                    define = arg.Split('=')[1];
                }
                else if (arg == "--ios")
                {
                    ios = true;
                }
                else if (arg == "--android")
                {
                    android = true;
                }
                else if (arg == "--osx")
                {
                    osx = true;
                }
                else if (arg == "--win")
                {
                    win = true;
                }
                else if (arg == "--debug")
                {
                    debug = true;
                }
                else if (arg.StartsWith("--target="))
                {
                    targetDirectory = arg.Split('=')[1];
                }
                else if (arg.StartsWith("--namespace="))
                {
                    nss = arg.Split('=')[1];
                    if (nss == "" && Resource.Settings.Namespace)
                    {
                        throw new NotSupportedException("namespace is open, must set ns");
                    }
                }
                else if (arg.StartsWith("--force-namespace"))
                {
                    forceNamespace = true;
                }
                else if (arg == "--server")
                {
                    server = true;
                }
            }
        }

        #region Bundle
        // 命令行生成Bundle
        static void Bundle()
        {
            ParseArgs();
            BundleProcess(AssetBundleOptimize.None);
        }

        static void BundleProcess(AssetBundleOptimize optimize)
        {
            if (Resource.Settings && !Resource.Settings.AssetBundle)
            {
                throw new NotSupportedException("Bundle未开启");
            }

            Debug.Log("====================>Start Bundle<====================");
            string[] nsList = nss.Split(',');
            foreach (var ns in nsList)
            {
                Debug.Log("====================>Process " + ns + "<====================");
                if (Resource.Settings.Namespace)
                {
                    // 开启namespace，按namespace存放
                    if (ns != "")
                    {
                        // 编译单个ns
                        BundleNamespace(ns, Path.Combine(bundleDirectory, ns), Path.Combine(targetDirectory, ns), optimize);
                    }
                    else
                    {
                        var dirs = AssetDatabase.GetSubFolders(bundleDirectory);
                        // 文件夹作为namespace
                        foreach (var d in dirs)
                        {
                            var name = Path.GetDirectoryName(d);
                            BundleNamespace(name, d, Path.Combine(targetDirectory, ns), optimize);
                        }
                    }
                }
                else
                {
                    // 不开启namespace，直接存放目标目录
                    var p = targetDirectory;
                    if (forceNamespace)
                    {
                        p = Path.Combine(targetDirectory, ns);
                    }
                    BundleNamespace(Resource.MainNamespace, bundleDirectory, p, optimize);
                }
            }

            Debug.Log("====================>End Bundle<====================");
            AssetDatabase.Refresh();
            ClearManifest();
        }

        static void BundleNamespace(string ns, string path, string targetPath, AssetBundleOptimize optimize)
        {
            var options = GenerateOptions(optimize);
            var builds = BundleWithPath(path, optimize);
            Debug.Log("Bundle Path:" + path);
            var nPath = Path.Combine(targetPath, Resource.LocalBundle);
            // namespace / build / bundle
            if (ios)
            {
                Debug.Log("====================>Start Bundle iOS<====================");
                var p = Path.Combine(nPath, BundleBuild.iOS);
                PathInit(p);
                BuildPipeline.BuildAssetBundles(p, builds, options, BuildTarget.iOS);
                Debug.Log("Bundle Namespace (" + ns + ") -> " + p);
            }

            if (android)
            {
                Debug.Log("====================>Start Bundle Android<====================");
                var p = Path.Combine(nPath, BundleBuild.Android);
                PathInit(p);
                BuildPipeline.BuildAssetBundles(p, builds, options, BuildTarget.Android);
                Debug.Log("Bundle Namespace (" + ns + ") -> " + p);
            }

            if (osx)
            {
                Debug.Log("====================>Start Bundle OSX<====================");
                var p = Path.Combine(nPath, BundleBuild.OSX);
                PathInit(p);
                var m = BuildPipeline.BuildAssetBundles(p, builds, options, BuildTarget.StandaloneOSX);
                Debug.Log("Bundle Namespace (" + ns + ") -> " + p);
            }

            if (win)
            {
                Debug.Log("====================>Start Bundle Win<====================");
                var p = Path.Combine(nPath, BundleBuild.WIN);
                PathInit(p);
                BuildPipeline.BuildAssetBundles(p, builds, options, BuildTarget.StandaloneWindows);
                Debug.Log("Bundle Namespace (" + ns + ") -> " + p);
            }
        }

        static void PathInit(string path)
        {
            var absPath = Path.Combine(Environment.CurrentDirectory, path);
            FileTools.DeleteFolder(absPath);
            Directory.CreateDirectory(absPath);
        }

        static BuildAssetBundleOptions GenerateOptions(AssetBundleOptimize optimize)
        {
            BuildAssetBundleOptions buildOption = BuildAssetBundleOptions.None;
            buildOption |= BuildAssetBundleOptions.AppendHashToAssetBundleName;
            // buildOption |= BuildAssetBundleOptions.StrictMode;
            if ((optimize & AssetBundleOptimize.NoCompression) > 0)
            {
                buildOption |= BuildAssetBundleOptions.UncompressedAssetBundle;
            }

            if (debug)
            {
                //                buildOption |= BuildAssetBundleOptions.UncompressedAssetBundle;
                // buildOption |= BuildAssetBundleOptions.ChunkBasedCompression;
            }
            else
            {
                // buildOption |= BuildAssetBundleOptions.ChunkBasedCompression;
                buildOption |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
            }

            return buildOption;
        }

        [Flags]
        public enum AssetBundleOptimize
        {
            None,
            SceneNoDep, // 场景不共享依赖
            NoCompression, // 不压缩
            DirNoCombine, // 目录不合并
        }

        public class AssetBundleBuildExtend
        {
            internal AssetBundleBuild build = new AssetBundleBuild();
            internal long size = 0;
            internal List<string> assets = new List<string>();
            internal List<string> dirs = new List<string>();

            public AssetBundleBuildExtend(string name, string v = null)
            {
                dirs = name.Split("/").ToList();
                build.assetBundleName = name.Replace('/', '-');
                if (v != null)
                {
                    build.assetBundleVariant = v;
                }
            }
            public AssetBundleBuild Get()
            {
                build.assetNames = assets.ToArray();
                return build;
            }
        }

        static bool BundleWithDepend(string asset, string path, List<string> allAssets, Dictionary<string, AssetBundleBuildExtend> buildMap)
        {
            var despends = AssetDatabase.GetDependencies(asset, true);
            foreach (var item in despends)
            {
                if (path != null && item.Contains(path))
                {
                    Debug.Log("filter1:" + item + "(" + path + ")");
                    continue;
                }
                if (!item.Contains("Assets/"))
                {
                    // Debug.Log("filter2:"+item);
                    continue;
                }
                // if (AssetDatabase.IsValidFolder(item))
                // {
                //     Debug.Log("filter3:"+item);
                //     continue;
                // }
                if (Path.GetExtension(item) == ".cs")
                {
                    // Debug.Log("filter4:"+item);
                    continue;
                }
                if (allAssets.Contains(item))
                {
                    // Debug.Log("filter5:"+item);
                    continue;
                }
                var itemD = Path.GetDirectoryName(item);
                var dir = itemD.Replace("Assets/", "").Replace(" ", "").Replace(".", "");
                // var dir = itemD.Replace(autoBundleDirectory, "").Replace('/', '-');
                if (!buildMap.TryGetValue(dir, out var extend))
                {
                    extend = new AssetBundleBuildExtend(dir);
                    buildMap.Add(dir, extend);
                }
                // Debug.Log(asset+"=>des:"+itemD+" = "+dir);
                if (extend.assets.Contains(item))
                {
                    continue;
                }
                extend.assets.Add(item);
                allAssets.Add(asset);

                var rr = BundleWithDepend(item, null, allAssets, buildMap);
                if (!rr)
                {
                    // extend.assets.Remove(item);
                    // allAssets.Remove(asset);
                    // return false;
                }
            }

            return true;
        }

        static AssetBundleBuild[] BundleWithPath(string path, AssetBundleOptimize optimize)
        {
            var dirs = AssetDatabase.GetSubFolders(path);
            List<AssetBundleBuildExtend> builds = new List<AssetBundleBuildExtend>();
            Dictionary<string, AssetBundleBuildExtend> buildMap = new Dictionary<string, AssetBundleBuildExtend>();
            List<string> allAssets = new List<string>();
            // 文件夹作为bundle
            foreach (var d in dirs)
            {
                var name = Path.GetFileName(d);
                var nn = name.Split(Resource.BundleVariant);
                var build = new AssetBundleBuildExtend(nn[0]);
                if (nn.Length > 1) build.build.assetBundleVariant = nn[1];
                // Debug.Log("Dir:"+name);
                var ll = AssetDatabase.FindAssets("*", new[] { d });
                foreach (var item in ll)
                {
                    var asset = AssetDatabase.GUIDToAssetPath(item);
                    var add = false;
                    var dep = false;
                    if (Path.GetExtension(asset) == ".unity")
                    {
                        // Scene
                        add = true;
                        if ((optimize & AssetBundleOptimize.SceneNoDep) == 0) dep = true;
                    }
                    else if (!AssetDatabase.IsValidFolder(asset))
                    {
                        if (Path.GetExtension(asset) == ".cs") continue;
                        if (build.assets.Contains(asset)) continue;
                        add = true;
                        dep = true;
                    }

                    if (!add) continue;
                    // Debug.Log(asset);
                    build.assets.Add(asset);
                    allAssets.Add(asset);
                    if (dep) BundleWithDepend(asset, path, allAssets, buildMap);
                }

                builds.Add(build);
            }

            if ((optimize & AssetBundleOptimize.DirNoCombine) == 0)
            {
                var maxDir = 0;
                foreach (var e in buildMap)
                {
                    var b = e.Value;
                    foreach (var ass in b.assets)
                    {
                        var file = new System.IO.FileInfo(ass);
                        b.size += file.Length;
                    }

                    if (maxDir == 0 || maxDir < b.dirs.Count)
                    {
                        maxDir = b.dirs.Count;
                    }
                }

                var change = 0;
                for (var i = maxDir; i >= 2; i--)
                {
                    change = 0;
                    var tmpBuildList = buildMap.Values.ToList();
                    foreach (var b in tmpBuildList)
                    {
                        if (b.size == 0)
                        {
                            continue;
                        }
                        if (b.dirs.Count != i)
                        {
                            continue;
                        }
                        if (b.size > 1024 * 1024 * 100)
                        {
                            Debug.Log("Fill size:" + b.build.assetBundleName + "=>" + (b.size - 1024 * 1024 * 16));
                            continue;
                        }
                        change += 1;
                        var dd = b.dirs.ToArray().ToList();
                        dd.RemoveAt(b.dirs.Count - 1);
                        var dir = string.Join("/", dd);
                        if (!buildMap.TryGetValue(dir, out var extend))
                        {
                            extend = new AssetBundleBuildExtend(dir);
                            buildMap.Add(dir, extend);
                        }
                        extend.assets.AddRange(b.assets);
                        extend.size += b.size;
                        b.assets.Clear();
                        b.size = 0;
                        // Debug.Log("Merge:" + b.build.assetBundleName + "=>" + dir);
                    }
                }
            }
            else
            {
                foreach (var e in buildMap)
                {
                    var b = e.Value;
                    foreach (var ass in b.assets)
                    {
                        var file = new System.IO.FileInfo(ass);
                        b.size += file.Length;
                    }
                }
            }


            foreach (var e in buildMap)
            {
                if (e.Value.size == 0)
                {
                    // Debug.Log("Merge:"+e.Value.build.assetBundleName+"=>"+string.Join("/", e.Value.dirs));
                    continue;
                }
                builds.Add(e.Value);

                // Debug.Log("ad dir bundle:"+e.Key);
            }
            return builds.FindAll(extend => extend.assets.Count > 0).ConvertAll(extend => extend.Get()).ToArray();
        }

        [MenuItem("Gj/Bundle Build/Base/Mac")]
        static void BundleBaseOsx()
        {
            osx = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.None);
        }
        [MenuItem("Gj/Bundle Build/Base/Win")]
        static void BundleBaseWin()
        {
            win = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.None);
        }

        [MenuItem("Gj/Bundle Build/Base/iOS")]
        static void BundleBaseIos()
        {
            ios = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.None);
        }

        [MenuItem("Gj/Bundle Build/Base/Android")]
        static void BundleBaseAndroid()
        {
            android = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.None);
        }
        [MenuItem("Gj/Bundle Build/Debug/Mac")]
        static void BundleDebugOsx()
        {
            osx = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.NoCompression | AssetBundleOptimize.DirNoCombine);
        }
        [MenuItem("Gj/Bundle Build/Debug/Win")]
        static void BundleDebugWin()
        {
            win = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.NoCompression | AssetBundleOptimize.DirNoCombine);
        }

        [MenuItem("Gj/Bundle Build/Debug/iOS")]
        static void BundleDebugIos()
        {
            ios = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.NoCompression | AssetBundleOptimize.DirNoCombine);
        }

        [MenuItem("Gj/Bundle Build/Debug/Android")]
        static void BundleDebugAndroid()
        {
            android = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.NoCompression | AssetBundleOptimize.DirNoCombine);
        }
        [MenuItem("Gj/Bundle Build/Scene/Mac")]
        static void BundleSceneOsx()
        {
            osx = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.SceneNoDep);
        }
        [MenuItem("Gj/Bundle Build/Scene/Win")]
        static void BundleSceneWin()
        {
            win = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.SceneNoDep);
        }

        [MenuItem("Gj/Bundle Build/Scene/iOS")]
        static void BundleSceneIos()
        {
            ios = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.SceneNoDep);
        }

        [MenuItem("Gj/Bundle Build/Scene/Android")]
        static void BundleSceneAndroid()
        {
            android = true;
            debug = true;
            BundleProcess(AssetBundleOptimize.SceneNoDep);
        }
        [MenuItem("Gj/ClearManifest")]
        static void ClearManifest()
        {
            string manifest = Path.Combine(Application.persistentDataPath, Resource.Settings.Manifest);
            if (File.Exists(manifest))
            {
                File.Delete(manifest);
            }
            string namespaceManifest = Path.Combine(Application.persistentDataPath, Resource.Settings.NamespaceManifest);
            if (File.Exists(namespaceManifest))
            {
                File.Delete(namespaceManifest);
            }
            UpdateNamespace();
        }
        [MenuItem("Gj/UpdateVersion")]
        static void UpdateVersion()
        {
            // 读取版本: 需要先设定好对应的Manifest
            string version = File.ReadAllText("VERSION").Replace("\r\n", "\n").Replace("\n", "");
            string manifest = Path.Combine(resourceDirectory, Resource.Settings.Manifest);
            string json = File.ReadAllText(manifest);
            if (File.Exists(manifest))
            {
                File.Delete(manifest);
            }

            var info = JSONObject.Parse(json);
            using (StreamWriter sw = new StreamWriter(manifest))
            {
                info.Add("version", version);
                info.Add("date", DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss"));
                sw.Write(info.ToString());
            }
            UpdateNamespace();
        }
        [MenuItem("Gj/UpdateNamespace")]
        static void UpdateNamespace()
        {
            // 读取基本Namespace
            string ns = Resource.Settings.ns;
            string namespaceManifest = Path.Combine(resourceDirectory, Resource.Settings.NamespaceManifest);
            // Debug.LogError("update namespace delete"+namespaceManifest+"->"+File.Exists(namespaceManifest));
            if (File.Exists(namespaceManifest))
            {
                File.Delete(namespaceManifest);
            }
            using (StreamWriter sw = new StreamWriter(namespaceManifest))
            {
                JSONObject info = new JSONObject();
                info.Add("version", DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss"));
                info.Add("local", true);
                JSONObject o = new JSONObject();
                o.Add(ns, info);
                sw.Write(o.ToString());

                Debug.LogError("update namespace info" + o.ToString());
            }
        }
        #endregion Bundle

        #region Build

        [MenuItem("Gj/Build/Android")]
        static void BuildAndroidInfo()
        {
            android = true;
            Build();
        }
        [MenuItem("Gj/Build/Ios")]
        static void BuildIosInfo()
        {
            ios = true;
            Build();
        }
        [MenuItem("Gj/Build/mac")]
        static void BuildOsxInfo()
        {
            osx = true;
            Build();
        }
        [MenuItem("Gj/Build/win")]
        static void BuildWinInfo()
        {
            win = true;
            Build();
        }
        [MenuItem("Gj/Build/Android-Bundle")]
        static void BuildAndroidBundleInfo()
        {
            android = true;
            bundle = true;
            Build();
        }
        [MenuItem("Gj/Build/Ios-Bundle")]
        static void BuildIosBundleInfo()
        {
            ios = true;
            bundle = true;
            Build();
        }
        [MenuItem("Gj/Build/Mac-Bundle")]
        static void BuildOsxBundleInfo()
        {
            osx = true;
            bundle = true;
            Build();
        }
        [MenuItem("Gj/Build/Win-Bundle")]
        static void BuildWinBundleInfo()
        {
            win = true;
            bundle = true;
            Build();
        }
        // 命令行打包
        static void Build()
        {
            ParseArgs();
            if (buildNumber == "")
            {
                buildNumber = File.ReadAllText("BUILD").Replace("BUILD_NUMBER=", "").Replace("\r\n", "\n").Replace("\n", "");
            }
            // 根据
            if (!server)
            {
                if (Resource.Settings.AssetBundle)
                {
                    FileTools.MoveFile(Path.Combine(targetDirectory, "Bundle"), "Steam-Bundle");
                }
                if (bundle)
                {
                    BundleProcess(AssetBundleOptimize.None);
                }

                if (Resource.Settings.ILRuntimeLocal)
                {
                    FileTools.MoveFile(Path.Combine(targetDirectory, "Projects"), "Projects");
                }

                if (ios)
                {
                    BuildIos();
                }

                if (android)
                {
                    BuildAndroid();
                }

                if (osx)
                {
                    BuildOsx();
                }

                if (win)
                {
                    BuildWin();
                    BuildWin64();
                }

                if (Resource.Settings.AssetBundle)
                {
                    FileTools.MoveFile("Bundle", Path.Combine(resourceDirectory, "Bundle"));
                }

                if (Resource.Settings.ILRuntimeLocal)
                {
                    FileTools.MoveFile("Projects", Path.Combine(targetDirectory, "Projects"));
                }
                if (Resource.Settings.AssetBundle)
                {
                    FileTools.MoveFile("Steam-Bundle", Path.Combine(targetDirectory, "Bundle"));
                }
            }


            if (server)
            {
                BuildServer();
            }
        }

        private static string[] GetBuildScenes()
        {
            List<string> scenes = new List<string>();
            // 自动解析项目
            // DirectoryInfo rootDir = Directory.GetCurrentDirectory();
            //            string root = Environment.CurrentDirectory;
            //#if UNITY_EDITOR_OSX
            //            string targetDir = root + @"/" + directory;
            //#elif UNITY_EDITOR_WIN
            //            string targetDir = root + @"\" + directory;
            //#endif
            //            DirectoryInfo dir = new DirectoryInfo(targetDir);
            //            foreach (DirectoryInfo dChild in dir.GetDirectories("*.unity"))
            //            {
            //                scenes.Add(directory+dChild.Name);
            //                Debug.Log("Add Scene:"+directory+dChild.Name);
            //            }

            foreach (EditorBuildSettingsScene e in EditorBuildSettings.scenes)
            {
                if (e == null)
                    continue;
                if (server)
                {
                    if (!e.path.ToLower().Contains("server"))
                    {
                        // 服务模式：只包含服务场景
                        continue;
                    }

                    // e.enabled = true;
                }
                else
                {
                    if (e.path.ToLower().Contains("server"))
                    {
                        // 普通模式：不包含服务场景
                        continue;
                    }

                    if (!e.enabled)
                    {
                        continue;
                    }

                    // if (e.path.ToLower().Contains("test"))
                    // {
                    //     e.enabled = true;
                    // }
                }
                Debug.Log("Add Scene:" + e.path);
                scenes.Add(e.path);
                // break;
            }

            return scenes.ToArray();
        }

        static void BuildIos()
        {
            // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, define);
            PlayerSettings.iOS.buildNumber = buildNumber;
            Regex r = new Regex("-.*");
            PlayerSettings.bundleVersion = r.Replace(version.Replace("v", ""), "");
            PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, ScriptingImplementation.IL2CPP);
            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "ios";
            buildPlayerOptions.target = BuildTarget.iOS;
            BuildOptions buildOption = BuildOptions.None;
            if (debug)
            {
                buildOption |= BuildOptions.Development;
                buildOption |= BuildOptions.AllowDebugging;
                buildOption |= BuildOptions.ConnectWithProfiler;
                buildOption |= BuildOptions.CompressWithLz4;
            }
            else
            {
                buildOption |= BuildOptions.CompressWithLz4HC;
            }

            buildOption |= BuildOptions.AcceptExternalModificationsToPlayer;

            buildPlayerOptions.options = buildOption;

            BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
            BuildSummary summary = report.summary;

            if (summary.result == BuildResult.Succeeded)
            {
                Debug.Log("Build iOS succeeded: " + summary.totalSize + " bytes");
            }

            if (summary.result == BuildResult.Failed)
            {
                Debug.Log("Build iOS failed");
            }
        }

        static void BuildAndroid()
        {
            // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);
            PlayerSettings.Android.androidIsGame = true;

            EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(BuildTarget.Android), BuildTarget.Android);
            EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
            EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
            EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.Generic;
            EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;
            EditorUserBuildSettings.buildAppBundle = true;

            if (debug)
            {
                EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSize);
                EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging;
                EditorUserBuildSettings.allowDebugging = true;
            }
            else
            {
                EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSpeed);
                EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;
                EditorUserBuildSettings.allowDebugging = false;
            }

            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
            // 格式化生成Version
            //            int a = 0;
            //            var v = version.Replace('v','').Split('-')[0].Split( '.');
            //            for (var i = 0; i < v.Length; i++)
            //            {
            //                a+= Int32.Parse(v[i]) * (10 ^ (v.Length-i-1));
            //            }
            PlayerSettings.Android.bundleVersionCode = Int32.Parse(buildNumber);
            PlayerSettings.bundleVersion = version;

            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "android";
            buildPlayerOptions.targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.Android);
            buildPlayerOptions.target = BuildTarget.Android;

            BuildOptions buildOption = BuildOptions.None;

            if (debug)
            {
                buildOption |= BuildOptions.Development;
                // buildOption |= BuildOptions.AllowDebugging;
                // buildOption |= BuildOptions.ConnectWithProfiler;
                buildOption |= BuildOptions.CompressWithLz4;
            }
            else
            {
                buildOption |= BuildOptions.CleanBuildCache;
                buildOption |= BuildOptions.CompressWithLz4HC;
            }

            buildOption |= BuildOptions.AcceptExternalModificationsToPlayer;

            buildPlayerOptions.options = buildOption;
            try
            {
                BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
                BuildSummary summary = report.summary;

                if (summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build Android succeeded: " + summary.totalSize + " bytes");
                }

                if (summary.result == BuildResult.Failed)
                {
                    Debug.Log("Build Android failed");
                }
            }
            catch (Exception e)
            {
                Debug.LogException(e);
                Debug.Log("Build Android failed");
            }
        }

        static void BuildOsx()
        {
            // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);
            // PlayerSettings.Android.androidIsGame = true;
            EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneOSX), BuildTarget.StandaloneOSX);
            // EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
            // EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
            // EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.Generic;
            // EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;
            // EditorUserBuildSettings.buildAppBundle = true;


            var buildTarget = BuildTarget.StandaloneOSX;
            var architecture = OSArchitecture.x64ARM64;
            EditorUserBuildSettings.SetPlatformSettings(BuildPipeline.GetBuildTargetName(buildTarget), "Architecture", architecture.ToString().ToLower());
            if (debug)
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSize);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging;
                EditorUserBuildSettings.allowDebugging = true;
            }
            else
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSpeed);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;
                EditorUserBuildSettings.allowDebugging = false;
            }

            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.Mono2x);
            // 格式化生成Version
            //            int a = 0;
            //            var v = version.Replace('v','').Split('-')[0].Split( '.');
            //            for (var i = 0; i < v.Length; i++)
            //            {
            //                a+= Int32.Parse(v[i]) * (10 ^ (v.Length-i-1));
            //            }
            PlayerSettings.bundleVersion = version;

            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "mac/mac";
            buildPlayerOptions.targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneOSX);
            buildPlayerOptions.target = BuildTarget.StandaloneOSX;

            BuildOptions buildOption = BuildOptions.None;

            if (debug)
            {
                buildOption |= BuildOptions.Development;
                // buildOption |= BuildOptions.AllowDebugging;
                // buildOption |= BuildOptions.ConnectWithProfiler;
                buildOption |= BuildOptions.CompressWithLz4;
            }
            else
            {
                buildOption |= BuildOptions.CleanBuildCache;
                buildOption |= BuildOptions.CompressWithLz4HC;
            }

            // buildOption |= BuildOptions.AcceptExternalModificationsToPlayer;

            buildPlayerOptions.options = buildOption;
            try
            {
                BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
                BuildSummary summary = report.summary;

                if (summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build OSX succeeded: " + summary.totalSize + " bytes");
                }

                if (summary.result == BuildResult.Failed)
                {
                    Debug.Log("Build OSX failed");
                }
            }
            catch (Exception e)
            {
                Debug.LogException(e);
                Debug.Log("Build OSX failed");
            }
        }

        static void BuildWin()
        {
            // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);
            // PlayerSettings.Android.androidIsGame = true;

            EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneWindows), BuildTarget.StandaloneWindows);
            // EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
            // EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
            // EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.Generic;
            // EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;
            // EditorUserBuildSettings.buildAppBundle = true;

            var buildTarget = BuildTarget.StandaloneWindows;
            var architecture = OSArchitecture.x86;
            EditorUserBuildSettings.SetPlatformSettings(BuildPipeline.GetBuildTargetName(buildTarget), "Architecture", architecture.ToString().ToLower());
            if (debug)
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSize);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging;
                EditorUserBuildSettings.allowDebugging = true;
            }
            else
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSpeed);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;
                EditorUserBuildSettings.allowDebugging = false;
            }

            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.Mono2x);
            // 格式化生成Version
            //            int a = 0;
            //            var v = version.Replace('v','').Split('-')[0].Split( '.');
            //            for (var i = 0; i < v.Length; i++)
            //            {
            //                a+= Int32.Parse(v[i]) * (10 ^ (v.Length-i-1));
            //            }
            // PlayerSettings.Android.bundleVersionCode = Int32.Parse(buildNumber);
            PlayerSettings.bundleVersion = version;


            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "win/win";
            buildPlayerOptions.targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneWindows);
            buildPlayerOptions.target = BuildTarget.StandaloneWindows;

            BuildOptions buildOption = BuildOptions.None;

            if (debug)
            {
                buildOption |= BuildOptions.Development;
                // buildOption |= BuildOptions.AllowDebugging;
                // buildOption |= BuildOptions.ConnectWithProfiler;
                buildOption |= BuildOptions.CompressWithLz4;
            }
            else
            {
                buildOption |= BuildOptions.CleanBuildCache;
                buildOption |= BuildOptions.CompressWithLz4HC;
            }

            // buildOption |= BuildOptions.AcceptExternalModificationsToPlayer;

            buildPlayerOptions.options = buildOption;
            try
            {
                BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
                BuildSummary summary = report.summary;

                if (summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build Win succeeded: " + summary.totalSize + " bytes");
                }

                if (summary.result == BuildResult.Failed)
                {
                    Debug.Log("Build Win failed");
                }
            }
            catch (Exception e)
            {
                Debug.LogException(e);
                Debug.Log("Build Win failed");
            }
        }

        static void BuildWin64()
        {
            // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);
            // PlayerSettings.Android.androidIsGame = true;

            EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneWindows64), BuildTarget.StandaloneWindows64);
            // EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
            // EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
            // EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.Generic;
            // EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;
            // EditorUserBuildSettings.buildAppBundle = true;
            var buildTarget = BuildTarget.StandaloneWindows;
            var architecture = OSArchitecture.x64;
            EditorUserBuildSettings.SetPlatformSettings(BuildPipeline.GetBuildTargetName(buildTarget), "Architecture", architecture.ToString().ToLower());
            if (debug)
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSize);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging;
                EditorUserBuildSettings.allowDebugging = true;
            }
            else
            {
                // EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
                // PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.Android, Il2CppCodeGeneration.OptimizeSpeed);
                // EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;
                EditorUserBuildSettings.allowDebugging = false;
            }

            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.Mono2x);
            // 格式化生成Version
            //            int a = 0;
            //            var v = version.Replace('v','').Split('-')[0].Split( '.');
            //            for (var i = 0; i < v.Length; i++)
            //            {
            //                a+= Int32.Parse(v[i]) * (10 ^ (v.Length-i-1));
            //            }
            // PlayerSettings.Android.bundleVersionCode = Int32.Parse(buildNumber);
            PlayerSettings.bundleVersion = version;

            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "win64/win";
            buildPlayerOptions.targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneWindows64);
            buildPlayerOptions.target = BuildTarget.StandaloneWindows64;

            BuildOptions buildOption = BuildOptions.None;

            if (debug)
            {
                buildOption |= BuildOptions.Development;
                // buildOption |= BuildOptions.AllowDebugging;
                // buildOption |= BuildOptions.ConnectWithProfiler;
                buildOption |= BuildOptions.CompressWithLz4;
            }
            else
            {
                buildOption |= BuildOptions.CleanBuildCache;
                buildOption |= BuildOptions.CompressWithLz4HC;
            }

            // buildOption |= BuildOptions.AcceptExternalModificationsToPlayer;

            buildPlayerOptions.options = buildOption;
            try
            {
                BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
                BuildSummary summary = report.summary;

                if (summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build Win64 succeeded: " + summary.totalSize + " bytes");
                }

                if (summary.result == BuildResult.Failed)
                {
                    Debug.Log("Build Win64 failed");
                }
            }
            catch (Exception e)
            {
                Debug.LogException(e);
                Debug.Log("Build Win64 failed");
            }
        }
        static void BuildServer()
        {
            var targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneLinux64);
            PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, define + ";UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP");

            // 格式化生成Version
            //            int a = 0;
            //            var v = version.Replace('v','').Split('-')[0].Split( '.');
            //            for (var i = 0; i < v.Length; i++)
            //            {
            //                a+= Int32.Parse(v[i]) * (10 ^ (v.Length-i-1));
            //            }
            // PlayerSettings.bundleVersion = version;
            EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Server;
            EditorUserBuildSettings.SwitchActiveBuildTarget(targetGroup, BuildTarget.StandaloneLinux64);

            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();

            buildPlayerOptions.scenes = GetBuildScenes();
            buildPlayerOptions.locationPathName = "server/server";
            // buildPlayerOptions.targetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget.StandaloneLinux64);
            buildPlayerOptions.target = BuildTarget.StandaloneLinux64;
            buildPlayerOptions.subtarget = (int)StandaloneBuildSubtarget.Server;
            // PlayerSettings.SetScriptingBackend(NamedBuildTarget.Server, ScriptingImplementation.Mono2x);

            BuildOptions buildOption = BuildOptions.None;
            if (debug)
            {
                buildOption |= BuildOptions.Development;
                buildOption |= BuildOptions.AllowDebugging;
                buildOption |= BuildOptions.ConnectWithProfiler;
            }

            buildPlayerOptions.options = buildOption;

            BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
            BuildSummary summary = report.summary;

            if (summary.result == BuildResult.Succeeded)
            {
                Debug.Log("Build Server succeeded: " + summary.totalSize + " bytes");
            }

            if (summary.result == BuildResult.Failed)
            {
                Debug.Log("Build Server failed");
            }
        }
        #endregion

        #region Project

        static void Project()
        {
            ParseArgs();
            try
            {
                ProjectProcess();
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }
        }
        static void ProjectProcess()
        {
            Debug.Log("====================>Start Project<====================");
            if (debug)
            {
                ILRuntimeEditor.configuration = "Debug";
            }
            else
            {
                // Unity依赖的Release没有宏，导致编译失败
                ILRuntimeEditor.configuration = "";
            }

            var root = Path.Combine(Environment.CurrentDirectory, targetDirectory);

            string[] nsList = nss.Split(',');
            foreach (var ns in nsList)
            {
                Debug.Log("====================>Process " + ns + "<====================");
                if (Resource.Settings.Namespace)
                {
                    // 开启namespace，以projectname作为namespace
                    if (ns != "")
                    {
                        // 编译单个ns
                        string p;
                        var result = ILRuntimeEditor.projects.TryGetValue(ns, out p);
                        if (result)
                        {
                            var target = Path.Combine(Path.Combine(root, ns), ILRuntimeEditor.targetDir);
                            FileTools.DeleteFolder(target);
                            ILRuntimeEditor.Compile(ns, p, target);
                        }
                    }
                    else
                    {
                        var e = ILRuntimeEditor.projects.GetEnumerator();
                        while (e.MoveNext())
                        {
                            var project = e.Current;
                            var target = Path.Combine(Path.Combine(root, project.Key), ILRuntimeEditor.targetDir);
                            FileTools.DeleteFolder(target);
                            ILRuntimeEditor.Compile(project.Key, project.Value, target);
                        }
                    }
                }
                else
                {
                    var e = ILRuntimeEditor.projects.GetEnumerator();
                    // 删除所有历史Project，重新生成
                    var target = root;
                    if (forceNamespace)
                    {
                        target = Path.Combine(root, ns);
                    }
                    target = Path.Combine(target, ILRuntimeEditor.targetDir);
                    FileTools.DeleteFolder(target);
                    while (e.MoveNext())
                    {
                        var project = e.Current;
                        ILRuntimeEditor.Compile(project.Key, project.Value, target);
                    }
                }
            }

            Debug.Log("====================>End Project<====================");
        }


        [MenuItem("Gj/Generate Project DLLs/Debug")]
        static void GenerateProjectDllsDebug()
        {
            debug = true;
            ProjectProcess();
        }

        [MenuItem("Gj/Generate Project DLLs/Release")]
        static void GenerateProjectDllsRelease()
        {
            debug = false;
            ProjectProcess();
        }

        [MenuItem("Gj/Generate CLR Binding Code")]
        static void GenerateCLRBinding()
        {
            //第二个参数为自动生成的代码保存在何处
            ILRuntimeEditor.GenerateCLRBinding();
        }
        #endregion
    }
}